namespace Brjnk.Maps
{
    using System;

    /// <summary>
    /// </summary>
    public class TimingProvider : ITimingProvider
    {
        private static TicksTime currentTime;
        private static Int32 lastTicks;

        private static object lck = new Object();

        private Action<TicksTime> tickInvocationList;

        private ITimer tickTimer;

        public TimingProvider()
        {
            UpdateTime();
            tickTimer = this.GetTimer();
            tickTimer.Elapsed += new Action(tickTimer_Elapsed);
        }

        public event Action<TicksTime> Tick
        {
            add
            {
                lock (lck)
                {
                    tickInvocationList += value;
                    if (tickInvocationList.GetInvocationList().Length == 1) StartTickTimer();
                }
            }

            remove
            {
                lock (lck)
                {
                    tickInvocationList -= value;
                    if (tickInvocationList.GetInvocationList().Length == 0) StopTickTimer();
                }
            }
        }

        public TicksTime GetTime()
        {
            lock (lck)
            {
                UpdateTime();
                return currentTime;
            }
        }

        public ITimer GetTimer()
        {
            return new Timer();
        }

        private static void UpdateTime()
        {
            lock (lck)
            {
                int currentTicks = Environment.TickCount;
                if (currentTicks < lastTicks)
                {
                    currentTime = currentTime.AddMilliseconds(Int32.MaxValue - lastTicks + ((long)currentTicks - Int32.MinValue));
                }
                else
                {
                    currentTime = currentTime.AddMilliseconds(Environment.TickCount - lastTicks);
                }
                lastTicks = currentTicks;
            }
        }

        private void StartTickTimer()
        {
            tickTimer.Change(1000, 1000);
        }

        private void StopTickTimer()
        {
            tickTimer.Change(-1, -1);
        }

        private void tickTimer_Elapsed()
        {
            tickInvocationList(GetTime());
        }
    }
}